package bold.deposit.useful;

import bold.deposit.Account;
import bold.storage.core.Record;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import lombok.extern.log4j.Log4j2;

import java.io.UnsupportedEncodingException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * JWT工具类
 */
@Log4j2
public class JWTUtil {
    private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";
    private static final ZoneId zoneId = ZoneId.systemDefault();

    private static Algorithm algorithm;
    private static JWTVerifier verifier;

    static {
        try {
            algorithm = Algorithm.HMAC256(SECRET);
        } catch (UnsupportedEncodingException e) {
            log.error("init JWTUtil error");
            e.printStackTrace();
        }
        verifier = JWT.require(algorithm).build();
    }

    public static String token(Object data) {
        return token(data, 30, TimeUnit.MINUTES);
    }

    /**
     * @param data     数据
     * @param time     过期时间
     * @param timeUnit 过期时间单位
     */
    public static String token(Object data, long time, TimeUnit timeUnit) {
        if (data == null) throw new IllegalArgumentException("参数不能为空");
        return JWT.create()
                .withClaim("account", JSON.toJSONString(data))
                .withExpiresAt(getDate(timeUnit.toSeconds(time)))
                .sign(algorithm);
    }

    /**
     * @param token
     * @param t     转换对象
     * @return json 字符串
     * @throws TokenExpiredException          token 过期
     * @throws SignatureVerificationException 校验验证失败
     */
    public static <T> T get(String token, Class<T> t) throws TokenExpiredException, SignatureVerificationException {
        if (token == null || "".equals(token)) throw new IllegalArgumentException("参数不能为空");
        return JSON.parseObject(get(token), t);
    }

    private static String get(String token) throws TokenExpiredException {
        return verifier.verify(token).getClaim("account").asString();
    }

    /**
     * @param time 多久后过期
     * @return 到期时间
     */
    private static Date getDate(long time) {
        Instant instant = LocalDateTime.now().plusSeconds(time).atZone(zoneId).toInstant();
        return Date.from(instant);
    }

    public static void main(String[] args) {
        Record record = new Record().set("id", 12346465).set("name", "我是人");
        //两个小时 后重新登录 直接失效 不用考虑延长失效时间
        String token = JWTUtil.token(record, 2, TimeUnit.HOURS);
        System.out.println(token);

        Account r = get(token + 1, Account.class);
        System.out.println(JSON.toJSONString(r));
    }
}
